# --------------------------------------------------------------------------------------------------------------------
# Project:             Digital Payment System (DPS)
# Website:             http://code.google.com/p/dps-x509/
# Purpose of document: This class validates and holds python representation 
#                      of csr values
# --------------------------------------------------------------------------------------------------------------------
import sys, string, logging

sys.path.append("..")

#we would prefer the try to pass, but the import stuff isn't working
try:
  import keyczar.keys as keys
except ImportError:
  from keyczar import *
  
import dps.csrAsn1Extractor
import dps.errors
import dps.utils

# --------------------------------------------------------------------------------------------------------------------
class Csr:
  """ Class that provides facade to keyzcar.utils functionality. """
 
# --------------------------------------------------------------------------------------------------------------------
  def __init__(self, extractor, privateKey= None):
    """ constructor 
    @param  extractor: that interfaces with asn1
    @type   extractor: dps.csrAsn1Extractor.CsrAsn1Extractor
    @param  privateKey: private key used to sign csr
    @type   privateKey: keys.RSAPublicKey
    """
    dps.utils.assertion(not privateKey or isinstance(privateKey, keys.RSAPublicKey), \
                        "Csr.__init__: Invalid privateKey")
    dps.utils.assertion(isinstance(extractor, dps.csrAsn1Extractor.CsrAsn1Extractor), \
                        "Csr.__init__: Invalid extractor")
    
    self.__extractor_ = extractor
    self.__privateKey_ = privateKey
    self.__issuerCertificate_ = None
    
# --------------------------------------------------------------------------------------------------------------------
  def eq(self, other):
    """ 
    equals operator. compares base 64 output 
    @rtype: bool 
    """
    return self.asBase64() == other.asBase64()

# --------------------------------------------------------------------------------------------------------------------
  def ne(self, other):
    """ 
    not equals operator. compares base 64 output 
    @rtype: bool 
    """
    return not self == other  
  
# --------------------------------------------------------------------------------------------------------------------
  @staticmethod  
  def load(certificate, privateKey= None):
    """ load a certificate from string file contents 
    @param certificate: must be in der or base64 string format
    @type  certificate: string
    @param privateKey: if None this will be generated
    @type  privateKey: None or keyczar.keys.RSAPrivateKey 

    @raise dps.errors.MissingRequiredParametersError: if required fields are missing. ie. token value, token type
      See http://code.google.com/p/dps-x509/wiki/ValueTokenDefinitions for more information
    @raise dps.errors.NoRSADataFoundError: if dsa or other pki algorithm is used. 
      RSA is currently the only supported.
    @raise dps.errors.InvalidSignatureError: if the signature does not match the certificate
    @raise dps.errors.DecodingError: if otherwise unable to create asn1 model from cert
    
    @rtype:  Csr
    """
    extractor = None
    dps.utils.assertion(not privateKey or isinstance(privateKey, keys.RsaPrivateKey), \
                        "Csr.load: Invalid privateKey")
    try:
      extractor = dps.csrAsn1Extractor.CsrAsn1Extractor(certificate)
    
    except dps.errors.DPSBaseError:
      raise
    except Exception, e:
      dps.utils.out("Exception in Csr.load: " + str(sys.exc_info()[0]) + str(e))
      raise dps.errors.DecodingError()
    
    dps.utils.assertion(extractor, "Csr.load: extractor not created")
    x509 = Csr(extractor, privateKey)
    return x509

  # --------------------------------------------------------------------------------------------------------------------
  def getParams(self):
    """ 
    get the properties out of this certificate
    @rtype: dps.csrParams.CsrParams
    """
    return self.__extractor_.getParams()
      
  # --------------------------------------------------------------------------------------------------------------------
  def verifySignature(self):
    """ 
    check if the public key can be used to verify the certificate
    @return: true if the certificate is verifed by the public key
    @rtype:  bool
    """    
    isOk = False
    try:
      rsaPubKey = self.getParams().getPublicKey()
      dps.utils.assertion(isinstance(rsaPubKey, keys.RsaPublicKey), \
                        "Csr.verifySignature: Invalid rsaPubKey")

      isOk = rsaPubKey.Verify(self.__extractor_.getTbsCertificateBytes(), self.__extractor_.getSignatureBytes())
    except Exception, e:
      dps.utils.out("Exception in Csr.verifySignature: " + str(sys.exc_info()[0]) + str(e))
    dps.utils.out("Result of Csr.verifySignature: " + str(isOk))
    
    return isOk
  
  # --------------------------------------------------------------------------------------------------------------------
  def asBase64(self):
    """ 
    base64 representation without header and footer 
    @rtype: string
    """
    return self.__extractor_.asBase64()
  
  # --------------------------------------------------------------------------------------------------------------------
  def prettyPrint(self):
    """ 
    returns string from asn1 pretty print 
    @rtype: string
    """
    return self.__extractor_.prettyPrint()
    
  # --------------------------------------------------------------------------------------------------------------------
  def privateKey(self):
    """ 
    returns private key or None if not set
    @rtype: keyczar.keys.RSAPrivateKey
    """
    return self.__privateKey_

  # --------------------------------------------------------------------------------------------------------------------
  def getSubjectAsBase64(self):
    """ 
    returns subject info
    @rtype: string
    """
    return self.__extractor_.getSubjectBase64()
  
# --------------------------------------------------------------------------------------------------------------------
if __name__ == "__main__":  
  try:
    base64 = """MIICUzCCATsCAQAwDjEMMAoGA1UEAxMDdGltMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAndyh3NZzIdKko7snKaIJrAAtVUS+vpQjEJW0lJA/zKsI7OxF
Ye0EsCi9JpNfLK2Vqaataqjui9QJdZLmHi3cTo7uQKdsL851V8QsJt+FOeKvws3q
BQe0wj/Tu1+QD2F0Oh4ArWjhxaCg7YAEKDLDLHgM599Npzq+QpF3EYyJqN2kK9Il
/+T6pd7/0DjJMbzuE6qx9CEIPTwPtaQ51+4G9nfTR9iNg8OdSVLbHyMAbynxvAY/
U1ZJSiYYdlwFp7H/Uc/SqI7j1e7HY63/OAoyZ/smHZeNrCzBRPH1GUagg7O9QE3C
oEKGM9QZM4LGBl3hjgkDbgpSxcXnO9EnbbnQewIDAQABAAAwDQYJKoZIhvcNAQEE
BQADggEBAF9YmwuN4hwpRRELR0oIw2R93kfxhHdOBcOOY/ld0YfJk9UE7knYcjVB
msQipL2W+xotmLBFJUCBP7pYyIHYQ0VfHDB/chRzvkKv8fkzA7SJFtICvRSqC773
QDGkG6l6/sQMFF43kOlTMTbsZdPxOJ/j3BeuJddfeANdaNIW1gZwK4DiJOF8e2F/
xGzsDRBTwi5ne/RCOgBT3uFG1T17EH9JHorpi2pOo4Fa9CsKFJbcrTB5xIX16uq4
8MNbiKS9lY5FPmzrJFbVqPt9yp/ZGzWWbmzeyNSlVvWO5eUzMAIqaa3QjAcK4bu5
DSrnvbe9TXgreVmK81qNq7ftK4itirI==="""
    
    cert = Csr.load(base64)
    cert.verifySignature()

  except Exception, e:
    dps.utils.out("An exception occured: " + str(sys.exc_info()[0]) + " " + str(e))
  